<?php

namespace App\Services\Address;

use App\Commons\Domain\Module\Financial\Entity\WalletEntity;
use App\Commons\Domain\Module\Financial\Model\Wallet;
use App\Commons\Domain\Module\UserCenter\Model\Member;
use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress;
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Key\Factory\HierarchicalKeyFactory;
use BitWasp\Bitcoin\Mnemonic\Bip39\Bip39SeedGenerator;
use Web3p\EthereumUtil\Util;

class AddressService
{
    public static int $i = 1;

    public function createAddress()
    {
        $math = Bitcoin::getMath();
        $network = Bitcoin::getNetwork();

        /**
         * $random = new Random();
         * // 生成随机数(initial entropy)
         * $entropy = $random->bytes(Bip39Mnemonic::MIN_ENTROPY_BYTE_LEN);
         * $bip39 = MnemonicFactory::bip39();
         *
         * // 通过随机数生成助记词
         * $mnemonic = $bip39->entropyToMnemonic($entropy);
         * echo "mnemonic: " . $mnemonic . PHP_EOL . PHP_EOL;
         **/

        $mnemonic = "spawn glare pipe wise expect hello shoulder float inner mesh slender oppose";
        // 通过助记词生成种子，传入可选加密串'zw-bitcoin'
        $seedGenerator = new Bip39SeedGenerator();
        $seed = $seedGenerator->getSeed($mnemonic, 'zw-bitcoin');
        echo "seed: " . $seed->getHex() . PHP_EOL;
        $hdFactory = new HierarchicalKeyFactory();
        $master = $hdFactory->fromEntropy($seed);

        // 私钥
        echo "master private key: " . $master->getPrivateKey()->getHex() . PHP_EOL;
        // 公钥
        echo "master public key: " . $master->getPublicKey()->getHex() . PHP_EOL . PHP_EOL;

        // 从主私钥、公钥生成比特币、以太坊账户数量


        $util = new Util();

        // 设置路径account
        /**
         * 路径参数：m / purpose' / coin' / account' / change / address_index
         * 1.m是固定的, Purpose也是固定的，值为44
         * 2.Coin type：代表的是币种，0代表比特币，1代表比特币测试链，60代表以太坊 => https://github.com/satoshilabs/slips/blob/master/slip-0044.md
         * 3.Account：代表这个币的账户索引，从0开始
         * 4.Change：常量0用于外部链，常量1用于内部链（也称为更改地址）。外部链用于在钱包外可见的地址（例如，用于接收付款）。内部链用于在钱包外部不可见的地址，用于返回交易变更。 (所以一般使用0)
         * 5.address_index：这就是地址索引，从0开始，代表生成第几个地址，官方建议，每个account下的address_index不要超过20
         */
        $hardened = $master->derivePath("44'/0'/" . self::$i++ . "'/0/0");

        $data['public_key'] = $hardened->getPublicKey()->getHex();
        $data['private_key'] = $hardened->getPrivateKey()->getHex();
        $data['private_key_wif'] = $hardened->getPrivateKey()->toWif($network);
        $data['address']['BTC'] = (new PayToPubKeyHashAddress($hardened->getPublicKey()->getPubKeyHash()))->getAddress();
        $data['address']['ETH'] = $util->publicKeyToAddress($util->privateKeyToPublicKey($hardened->getPrivateKey()->getHex()));

        return $data;
    }

    public function createWallet()
    {
        $data = $this->createAddress();
        $uid = Member::find(1)->uid;
        $coin_id = 1;
        $address = $data['address']['ETH'];
        $private_key = $data['private_key'];
        return app(Wallet::class)->create(compact('uid', 'coin_id', 'address', 'private_key'));
    }
}
